package com.zxy.paycenter.common.aop;

import com.xiaoleilu.hutool.crypto.SecureUtil;
import com.zxy.paycenter.common.config.AlipayConfig;
import com.zxy.paycenter.common.constants.Constant;
import com.zxy.paycenter.common.constants.MessageResultConstant;
import com.zxy.paycenter.common.message.response.BaseResp;
import com.zxy.paycenter.common.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Properties;

/**
 * @author zxy
 */
@Aspect
@Component
@Slf4j
@Order(value = 1)
public class ParamValidAspect {

    @Around(value = "@annotation(com.zxy.paycenter.common.aop.RequireSignature)")
    public Object verifySign(ProceedingJoinPoint pjp) throws Throwable {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes != null) {
            HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
            if (request != null) {
                String requestId = request.getHeader("requestId");
                String channelNo = request.getHeader("channelNo");
                long timeStamp = Long.parseLong(request.getHeader("timeStamp"));
                String hmac = request.getHeader("hmac");
                String version = request.getHeader("version");
                long second = DateUtils.secondDiffTimeStamp(timeStamp);
                if (StringUtils.isBlank(hmac)) {
                    log.error("hmac签名参数不能为空");
                    return new BaseResp<>(null, MessageResultConstant.SIGN_ERROR, "hmac签名参数不能为空");
                }
                if (second > Constant.TIMESTAMP_MAX_SECOND_TIME) {
                    log.error("时间戳超时:{}", second);
                    return new BaseResp<>(null, MessageResultConstant.SIGN_ERROR, "请求时间戳非法,必须在" + Constant.TIMESTAMP_MAX_SECOND_TIME + "秒以内");
                }
                String secretHmac = "requestId=" + requestId + "&channelNo=" + channelNo + "&timeStamp=" + timeStamp + "&version=" + version;
                secretHmac = secretHmac + "we73hg3";
                secretHmac = SecureUtil.md5(secretHmac).toUpperCase();
                log.info(secretHmac);
                if (!hmac.equals(secretHmac)) {
                    log.error("验签异常");
                    return new BaseResp<>(null, MessageResultConstant.SIGN_ERROR, "验签异常");
                } else {
                    boolean isJump = getHttpServletRequest(request, channelNo);
                    if (isJump) {
                        return pjp.proceed();
                    } else {
                        return new BaseResp<>(null, MessageResultConstant.SIGN_ERROR, "没有对应的商户配置文件");
                    }
                }
            } else {
                log.error("请求HttpServletRequest对象为空");
                return new BaseResp<>(null, MessageResultConstant.SIGN_ERROR, "请求HttpServletRequest对象为空");
            }
        } else {
            log.error("缺少请求信息");
            return new BaseResp<>(null, MessageResultConstant.SIGN_ERROR, "缺少请求信息");
        }
    }

    /**
     * 根据渠道号获取不同渠道对应配置信息
     *
     * @param request   请求类
     * @param channelNo 渠道号
     * @throws IOException 异常
     */
    private boolean getHttpServletRequest(HttpServletRequest request, String channelNo) throws IOException {
        boolean result = false;
        channelNo = channelNo.toLowerCase();
        Properties properties = new Properties();
        // 使用ClassLoader加载properties配置文件生成对应的输入流
        InputStream in = AlipayConfig.class.getClassLoader().getResourceAsStream("alipay-config-" + channelNo + ".properties");
        if (in != null) {
            // 使用properties对象加载输入流
            properties.load(new InputStreamReader(in));
            //获取key对应的value值
            request.setAttribute("aliConfig", properties);
            in.close();
            result = true;
        } else {
            log.info("没有对应的商户配置文件");
        }
        return result;
    }
}
